//===================================================================
// 项目名 : Hbt.Application
// 文件名 : HbtProdMaterialService.cs
// 创建者 : Claude
// 创建时间: 2024-12-01
// 版本号 : V0.0.1
// 描述: 生产物料服务实现
//===================================================================

using Hbt.Application.Dtos.Logistics.Material.Master;
using Hbt.Application.Services.Logistics.Material.Master;
using Hbt.Common.Models;
using Hbt.Domain.Entities.Logistics.Material.Master;
using Hbt.Domain.IServices.Extensions;
using Hbt.Common.Utils;

using Microsoft.AspNetCore.Http;
using SqlSugar;
using System.Linq.Expressions;
using System.Collections.Generic;

namespace Hbt.Application.Services.Logistics.Material.Master
{
    /// <summary>
    /// 生产物料服务实现
    /// </summary>
    public class HbtProdMaterialService : HbtBaseService, IHbtProdMaterialService
    {
        /// <summary>
        /// 仓储工厂
        /// </summary>
        protected readonly IHbtRepositoryFactory _repositoryFactory;

        /// <summary>
        /// 获取生产物料仓储
        /// </summary>
        private IHbtRepository<HbtProdMaterial> ProdMaterialRepository => _repositoryFactory.GetBusinessRepository<HbtProdMaterial>();

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="repositoryFactory">仓储工厂</param>
        /// <param name="logger">日志服务</param>
        /// <param name="httpContextAccessor">HTTP上下文访问器</param>
        /// <param name="currentUser">当前用户服务</param>
        /// <param name="localization">本地化服务</param>
        public HbtProdMaterialService(
            IHbtRepositoryFactory repositoryFactory,
            IHbtLogger logger,
            IHttpContextAccessor httpContextAccessor,
            IHbtCurrentUser currentUser,
            IHbtLocalizationService localization) : base(logger, httpContextAccessor, currentUser, localization)
        {
            _repositoryFactory = repositoryFactory ?? throw new ArgumentNullException(nameof(repositoryFactory));
        }

        /// <summary>
        /// 获取生产物料分页列表
        /// </summary>
        /// <param name="query">查询条件</param>
        /// <returns>返回分页结果</returns>
        public async Task<HbtPagedResult<HbtProdMaterialDto>> GetListAsync(HbtProdMaterialQueryDto query)
        {
            var predicate = QueryExpression(query);
            var result = await ProdMaterialRepository.GetPagedListAsync(
                predicate,
                query?.PageIndex ?? 1,
                query?.PageSize ?? 10,
                x => x.CreateTime,
                OrderByType.Desc);

            var dtoResult = new HbtPagedResult<HbtProdMaterialDto>
            {
                TotalNum = result.TotalNum,
                PageIndex = query?.PageIndex ?? 1,
                PageSize = query?.PageSize ?? 10,
                Rows = result.Rows.Adapt<List<HbtProdMaterialDto>>()
            };

            return dtoResult;
        }

        /// <summary>
        /// 根据ID获取生产物料详情
        /// </summary>
        /// <param name="id">生产物料ID</param>
        /// <returns>返回生产物料详情</returns>
        public async Task<HbtProdMaterialDto> GetByIdAsync(long id)
        {
            var prodMaterial = await ProdMaterialRepository.GetByIdAsync(id);
            if (prodMaterial == null)
                throw new HbtException(L("ProdMaterial.NotFound", id));

            return prodMaterial.Adapt<HbtProdMaterialDto>();
        }

        /// <summary>
        /// 根据工厂编码和物料编码获取生产物料详情
        /// </summary>
        /// <param name="plantCode">工厂编码</param>
        /// <param name="materialCode">物料编码</param>
        /// <returns>返回生产物料详情</returns>
        public async Task<HbtProdMaterialDto> GetByPlantAndMaterialCodeAsync(string plantCode, string materialCode)
        {
            var prodMaterial = await ProdMaterialRepository.GetFirstAsync(x => 
                x.PlantCode == plantCode && x.MaterialCode == materialCode);
            
            if (prodMaterial == null)
                throw new HbtException(L("ProdMaterial.NotFoundByCode", plantCode, materialCode));

            return prodMaterial.Adapt<HbtProdMaterialDto>();
        }

        /// <summary>
        /// 创建生产物料
        /// </summary>
        /// <param name="input">创建对象</param>
        /// <returns>返回生产物料ID</returns>
        public async Task<long> CreateAsync(HbtProdMaterialCreateDto input)
        {
            // 验证生产物料是否已存在（工厂编码+物料编码组合）
            var fieldValues = new Dictionary<string, string>
            {
                { "PlantCode", input.PlantCode },
                { "MaterialCode", input.MaterialCode }
            };
            await HbtValidateUtils.ValidateFieldsExistsAsync(ProdMaterialRepository, fieldValues);

            var entity = input.Adapt<HbtProdMaterial>();
            var id = await ProdMaterialRepository.CreateAsync(entity);
            
            return id;
        }

        /// <summary>
        /// 更新生产物料
        /// </summary>
        /// <param name="input">更新对象</param>
        /// <returns>返回是否成功</returns>
        public async Task<bool> UpdateAsync(HbtProdMaterialUpdateDto input)
        {
            var entity = await ProdMaterialRepository.GetByIdAsync(input.MaterialId);
            if (entity == null)
                throw new HbtException(L("ProdMaterial.NotFound", input.MaterialId));

            input.Adapt(entity);
            var result = await ProdMaterialRepository.UpdateAsync(entity);
            
            return result > 0;
        }

        /// <summary>
        /// 删除生产物料
        /// </summary>
        /// <param name="id">生产物料ID</param>
        /// <returns>返回是否成功</returns>
        public async Task<bool> DeleteAsync(long id)
        {
            var entity = await ProdMaterialRepository.GetByIdAsync(id);
            if (entity == null)
                throw new HbtException(L("ProdMaterial.NotFound", id));

            var result = await ProdMaterialRepository.DeleteAsync(id);
            
            return result > 0;
        }

        /// <summary>
        /// 批量删除生产物料
        /// </summary>
        /// <param name="ids">生产物料ID集合</param>
        /// <returns>返回是否成功</returns>
        public async Task<bool> BatchDeleteAsync(long[] ids)
        {
            if (ids == null || ids.Length == 0)
                return false;

            var entities = await ProdMaterialRepository.GetListAsync(x => ids.Contains(x.Id));
            if (entities == null || !entities.Any())
                return false;

            var result = await ProdMaterialRepository.DeleteAsync(ids);
            
            return result > 0;
        }

        /// <summary>
        /// 更新生产物料状态
        /// </summary>
        /// <param name="input">状态更新对象</param>
        /// <returns>返回是否成功</returns>
        public async Task<bool> UpdateStatusAsync(HbtProdMaterialStatusDto input)
        {
            var entity = await ProdMaterialRepository.GetByIdAsync(input.MaterialId);
            if (entity == null)
                throw new HbtException(L("ProdMaterial.NotFound", input.MaterialId));

            entity.Status = input.Status;
            entity.Remark = input.Remark;

            var result = await ProdMaterialRepository.UpdateAsync(entity);
            
            return result > 0;
        }

        /// <summary>
        /// 导入生产物料数据
        /// </summary>
        /// <param name="fileStream">Excel文件流</param>
        /// <param name="sheetName">工作表名称</param>
        /// <returns>导入结果</returns>
        public async Task<(int success, int fail)> ImportAsync(Stream fileStream, string sheetName = "生产物料信息")
        {
            var importDtos = await HbtExcelHelper.ImportAsync<HbtProdMaterialImportDto>(fileStream, sheetName);
            if (importDtos == null || !importDtos.Any())
                return (0, 0);

            var success = 0;
            var fail = 0;

            foreach (var dto in importDtos)
            {
                try
                {
                    var material = dto.Adapt<HbtProdMaterial>();
                    await ProdMaterialRepository.CreateAsync(material);
                    success++;
                }
                catch (Exception ex)
                {
                    _logger.Error(L("ProdMaterial.ImportFailed", dto.MaterialCode), ex);
                    fail++;
                }
            }

            return (success, fail);
        }

        /// <summary>
        /// 导出生产物料数据
        /// </summary>
        /// <param name="query">查询条件</param>
        /// <param name="sheetName">工作表名称</param>
        /// <returns>Excel文件字节数组</returns>
        public async Task<(string fileName, byte[] content)> ExportAsync(HbtProdMaterialQueryDto query, string sheetName = "生产物料信息")
        {
            var predicate = QueryExpression(query);

            var materials = await ProdMaterialRepository.AsQueryable()
                .Where(predicate)
                .OrderBy(x => x.CreateTime)
                .ToListAsync();

            var exportDtos = materials.Adapt<List<HbtProdMaterialExportDto>>();
            
            return await HbtExcelHelper.ExportAsync(exportDtos, sheetName);
        }

        /// <summary>
        /// 获取导入模板
        /// </summary>
        /// <param name="sheetName">工作表名称</param>
        /// <returns>Excel文件字节数组</returns>
        public async Task<(string fileName, byte[] content)> GetTemplateAsync(string sheetName = "生产物料信息")
        {
            var template = new List<HbtProdMaterialTemplateDto>();
            return await HbtExcelHelper.ExportAsync(template, sheetName);
        }

        /// <summary>
        /// 获取生产物料选项列表
        /// </summary>
        /// <param name="plantCode">工厂编码</param>
        /// <param name="keyword">关键词</param>
        /// <returns>返回选项列表</returns>
        public async Task<List<HbtProdMaterialDto>> GetOptionsAsync(string plantCode, string? keyword = null)
        {
            Expression<Func<HbtProdMaterial, bool>> predicate = x => x.PlantCode == plantCode && x.Status == 1;
            
            if (!string.IsNullOrEmpty(keyword))
            {
                predicate = x => x.PlantCode == plantCode && x.Status == 1 && 
                                (x.MaterialCode.Contains(keyword) || x.MaterialDescription.Contains(keyword));
            }

            var entities = await ProdMaterialRepository.GetListAsync(predicate);
            return entities.Adapt<List<HbtProdMaterialDto>>();
        }



        /// <summary>
        /// 构建查询表达式
        /// </summary>
        /// <param name="query">查询条件</param>
        /// <returns>返回查询表达式</returns>
        private Expression<Func<HbtProdMaterial, bool>> QueryExpression(HbtProdMaterialQueryDto query)
        {
            var exp = Expressionable.Create<HbtProdMaterial>();

            if (query != null)
            {
                if (!string.IsNullOrEmpty(query.PlantCode))
                    exp = exp.And(x => x.PlantCode.Contains(query.PlantCode));

                if (!string.IsNullOrEmpty(query.MaterialCode))
                    exp = exp.And(x => x.MaterialCode.Contains(query.MaterialCode));

                if (!string.IsNullOrEmpty(query.MaterialDescription))
                    exp = exp.And(x => x.MaterialDescription.Contains(query.MaterialDescription));

                if (!string.IsNullOrEmpty(query.MaterialType))
                    exp = exp.And(x => x.MaterialType.Contains(query.MaterialType));

                if (!string.IsNullOrEmpty(query.MaterialGroup))
                    exp = exp.And(x => x.MaterialGroup.Contains(query.MaterialGroup));

                // Status: -1 表示显示全部
                if (query.Status.HasValue && query.Status.Value != -1)
                    exp = exp.And(x => x.Status == query.Status.Value);
            }

            return exp.ToExpression();
        }
    }
}
